/*
|-----------------------------------------------------------------------------|
| Overall ANTLR Grammar File Structure                                        |
|-----------------------------------------------------------------------------|
|	«grammarType» grammar name;
|		«optionsSpec»     = options { ... }
|		«tokensSpec»      = tokens { ... }
|		«attributeScopes» = «@action-scope-name::action-name» { ... }
|		«actions»
|		// rules
|		rule1 : ... ;
|		rule2 : ... ;
|		...
|_____________________________________________________________________________|
|		«grammarType»         = ( lexer | parser | tree | <empty> )
|   «optionsSpec»         = options { ... }
|   «tokensSpec»          = tokens { ... }
|   «attributeScopes»     = 
|   «actions»             = @«action-scope-name»::«action-name» { ... }
|    «action-scope-name» = ( lexer | parser | tree | <empty> = parser )
|    «action-name»       = ( header | members | rulecatch | synpredgate )
|-----------------------------------------------------------------------------|
*/
lexer grammar CLexer;

  options {
    language = Java;
  }// options

  @lexer::header {
    package pl.p04;
    import pl.p04.MyToken;
  }// header
  @lexer::members {
    /**
     *  The standard method called to automatically emit a token at the outermost lexical rule.
     *  The token object should point into the char buffer start..stop. If there is a text override
     *  in 'text', use that to set the token's text. Override this method to emit custom Token objects.
     *
     *  If you are building trees, then you should also override Parser or TreeParser.getMissingSymbol(). 
     *
     *  References:
     *   http://www.antlr.org/api/Java/classorg_1_1antlr_1_1runtime_1_1_lexer.html
     */
    @Override
    public Token emit() {
      MyToken t = new MyToken(input, state.type, state.channel, state.tokenStartCharIndex, getCharIndex()-1);
      t.setLine(state.tokenStartLine);
      t.setText(state.text);
      t.setCharPositionInLine(state.tokenStartCharPositionInLine);
      emit(t);
      // Tratar nuevo atributo
      if (input.getClass().getName().matches(".*ANTLRFileStream.*$"))
        t.setFileName(this.getSourceName());
      else
        t.setFileName("InputStream");
      return t;
    }// emit

  }// members

//= Rules ====================================================================|
   /* Tipos de datos */
   Void  : 'void';
   Int   : 'int';
   Char  : 'char';
   Float : 'float';

   /* Palabras reservadas */
   If    : 'if';
   While : 'while';
   For   : 'for';
   Do    : 'do';
   True  : 'true';
   False : 'false';    

  /* Nueva línea */
  fragment NewLine: '\r'? '\n';

  /* Dígitos */
  fragment Digit: '0'..'9';

  /* Letras */
  fragment Letter: ('a'..'z') | ('A'..'Z') | '_';

  /* Espacios */
  Space : (' ' | '\t' | NewLine ) { $channel=HIDDEN; skip(); };

  /* Números */
  Number : (Digit)+ ;

  /* Identificadores */
  Id: Letter (Letter | Digit)*;

  /* Cadenas */
  String: '\"' (~('\"'))* '\"';

  /* Separadores */
  LeftParenthesis: '(';
  RightParenthesis: ')';
  LeftBracket: '{';
  RightBracket: '}';
  Colon: ':';
  SemiColon: ';';
  Comma: ',';
  Amp: '&';
  Slash: '/';

  /* Operadores */
  Assing: '=';
  Less: '<';
  Greater: '>';
  Plus: '+';
  Minus: '-';
  Asterisk: '*';

  /* Comentarios */
  CommentLine
    : '//' (options {greedy=false;}: .)* NewLine 
      { $channel=HIDDEN; skip(); }
    ;
  NestedCommentBlock
    : '/*' (options {greedy=false;} : (NestedCommentBlock | .))* '*/'
      { $channel=HIDDEN; skip(); }
    ;
